package com.kira.scaffoldmvc.Strategy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 默认的Bean容器实现，用于管理和存储类型为V的策略Bean，通过键K进行索引
 * 实现了ApplicationContextAware接口以获取Spring应用上下文
 * 实现了InitializingBean接口以便在Bean属性设置完成后执行初始化逻辑
 * 实现了BeanContainer接口定义的核心方法
 */
//ApplicationContextAware 接口,让 Bean 能够获取 Spring 的 ApplicationContext（应用上下文），从而访问 Spring 容器中的其他 Bean 或资源
//InitializingBean 接口,当一个 Bean 实现了 InitializingBean 接口，Spring 在完成该 Bean 的所有属性注入后（初始化），会自动调用 afterPropertiesSet() 方法
//类似于 XML 配置中的 init-method 或 @PostConstruct 注解
public abstract class DefaultBeanContainer<K, V> implements ApplicationContextAware, InitializingBean, BeanContainer<K, V> {

    // Spring应用上下文，用于获取容器中的Bean
    protected ApplicationContext applicationContext;

    // 泛型参数V的实际Class类型，通过反射获取
    protected Class<?> type;

    // 存储键值对的内部映射，键为K，值为V类型的Bean
    private Map<K, V> beanMap;

    /**
     * 加载所有策略Bean到容器中
     * 调用抽象方法createBeanMap()获取映射关系并赋值给内部beanMap
     */
    public void loadBeans() {
        this.beanMap = this.createBeanMap();
    }

    /**
     * 由子类实现的抽象方法，用于创建具体的Bean映射关系
     * 通常通过applicationContext.getBeansOfType()方法获取特定类型的所有Bean
     * @return 包含键值映射关系的Map
     */
    protected abstract Map<K, V> createBeanMap();

    /**
     * Bean初始化完成后自动调用的方法
     * 1. 通过反射获取泛型参数V的实际类型
     * 2. 调用loadBeans()方法加载所有策略Bean
     */
    @Override
    public void afterPropertiesSet() {
        // 获取当前类的泛型父类类型
        Type genericSuperclass = this.getClass().getGenericSuperclass();

        // 转换为参数化类型以便获取泛型参数
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;

        // 获取实际的泛型参数数组（对于DefaultBeanContainer<K, V>有两个参数）
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

        // 获取第二个泛型参数V的类型
        Type valueType = actualTypeArguments[1];

        // 处理泛型参数是带泛型的类型的情况（例如List<String>）
        if (valueType instanceof ParameterizedType) {
            this.type = (Class<?>) ((ParameterizedType) valueType).getRawType();
        } else {
            // 普通类型直接转换为Class
            this.type = (Class<?>) actualTypeArguments[1];
        }

        // 加载所有策略Bean
        this.loadBeans();
    }

    /**
     * 实现ApplicationContextAware接口的方法，由Spring自动调用注入应用上下文
     * @param applicationContext Spring应用上下文
     */
    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 根据键获取对应的策略Bean
     * @param key 查找Bean的键
     * @return 对应的策略Bean，如果不存在则返回null
     */
    @Override
    public V getBean(K key) {
        return beanMap.get(key);
    }

    /**
     * 获取容器中所有策略Bean的集合
     * @return 包含所有策略Bean的集合
     */
    @Override
    public Collection<V> getBeans() {
        return new ArrayList<>(beanMap.values());
    }

    /**
     * 获取容器中所有策略Bean的不可变映射
     * @return 包含所有键值对的Map副本
     */
    @Override
    public Map<K, V> getBeansMap() {
        return new HashMap<>(beanMap);
    }
}